#include "Levels.h"
#include <opencv2\imgproc\imgproc.hpp>

Levels::Levels(double lowerBounds, double upperBounds) : Filter(1, 1), lowerBounds(lowerBounds), upperBounds(upperBounds)
{
}


Levels::~Levels(void)
{
}

void Levels::Process()
{
	outputs[0] = cv::Mat(inputs[0]->rows, inputs[0]->cols, inputs[0]->type());

	cv::Mat gray;
	cv::cvtColor(*inputs[0], gray, CV_BGR2GRAY);

	int hist[256];
	for (int *p = hist; p != hist + 256; ++p)
		*p = 0;

	for (int i = 0; i < gray.rows; ++i)
	{
		uchar *p = gray.ptr<uchar>(i);
		for (int j = 0; j < gray.cols; ++j)
		{
			hist[p[j]]++;
		}
	}

	for (int i = 1; i < 256; ++i)
	{
		hist[i] = hist[i] + hist[i-1];
	}

	int pixels = gray.cols * gray.rows;

	uchar min = 0;
	uchar max = 255;

	int lowerThreshold = lowerBounds * pixels + 0.5f;
	int upperThreshold = (1 - upperBounds) * pixels + 0.5f;

	for (int i = 0; i < 256; ++i)
	{
		if (hist[i] >= lowerThreshold)
		{
			min = i;
			break;
		}
	}

	for (int i = 255; i >= 0; --i)
	{
		if (hist[i] <= upperThreshold)
		{
			max = i;
			break;
		}
	}

	//look up table
	cv::Mat lut(1, 256, CV_8UC1);
	uchar *l = lut.ptr<uchar>(0);
	for (int i = 0; i < 256; ++i)
	{
		l[i] = cv::saturate_cast<uchar>((i - min) * 255 / (max - min));
	}

	cv::LUT(*inputs[0], lut, outputs[0]);
}
